﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Interface;
using Model;
using System.Threading;
using System.ServiceModel;
using CC;

namespace Controller
{
    public delegate void Update();
    
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class ClsController : IClsController
    {
        Random R;
        ClsKanalCol Kanaler;
        ClsPumpeCol Pumper;
        bool FriAdministration;

        ICController C;

        public Queue<string> Messages { get; private set; }

        public ClsController()
        {
            R = new Random();
            Messages = new Queue<string>();

            this.Pumper = new ClsPumpeCol(this);
            this.Kanaler = new ClsKanalCol(this);
            this.FriAdministration = true;

            Kanaler.TilføjKanal(0, -7, 10000, "...");
            Kanaler.TilføjKanal(1, -6, 10000, "...");
            Kanaler.TilføjKanal(2, -6, 10000, "...");
            Kanaler.TilføjKanal(3, -5, 10000, "...");
            Kanaler.TilføjKanal(4, -4, 10000, "...");

            Pumper.TilføjPumpe(1, "...", 100, (IClsKanal)Kanaler.Kanaler[0], (IClsKanal)Kanaler.Kanaler[1]);
            Pumper.TilføjPumpe(2, "...", 100, (IClsKanal)Kanaler.Kanaler[0], (IClsKanal)Kanaler.Kanaler[1]);


            Pumper.TilføjPumpe(3, "...", 100, (IClsKanal)Kanaler.Kanaler[1], (IClsKanal)Kanaler.Kanaler[2]);
            Pumper.TilføjPumpe(4, "...", 100, (IClsKanal)Kanaler.Kanaler[1], (IClsKanal)Kanaler.Kanaler[2]);


            Pumper.TilføjPumpe(7, "...", 100, (IClsKanal)Kanaler.Kanaler[2], (IClsKanal)Kanaler.Kanaler[3]);
            Pumper.TilføjPumpe(8, "...", 100, (IClsKanal)Kanaler.Kanaler[2], (IClsKanal)Kanaler.Kanaler[3]);


            Pumper.TilføjPumpe(9, "...", 100, (IClsKanal)Kanaler.Kanaler[3], (IClsKanal)Kanaler.Kanaler[4]);
            Pumper.TilføjPumpe(10, "...", 100, (IClsKanal)Kanaler.Kanaler[3], (IClsKanal)Kanaler.Kanaler[4]);
        }

        public void Start(int Nr)
        {
            ChannelFactory<ICController> F = new ChannelFactory<ICController>(new NetTcpBinding(), "net.tcp://localhost:54321/");
            this.C = F.CreateChannel();
            this.C.Connect(Nr);
        }

        void test()
        {
            while (true)
            {
                Thread.Sleep(5000);
                SetVandstand(1, R.Next(0, 40000), DateTime.Now);
            }
        }

        public void AddMessage(string txt)
        {
            lock (this.Messages)
            {
                this.Messages.Enqueue(txt);
            }
        }

        public void SetVandstand(int KanalId, double Vandstand, DateTime Dato)
        {
            ClsKanal Kanal = (ClsKanal)this.Kanaler.Kanaler.SingleOrDefault(val => val.Id == KanalId);
            if (Kanal != null)
            {
                Write("Ny vandstand i Kanal: " + Kanal.Id + " => " + Vandstand + " - " + Vandstand / Kanal.kapacitet * 100 + "%");
                if (this.FriAdministration)
                {
                    if (Vandstand == 0.0)
                        this.Pumper.SlukAlle(Kanal);
                    else
                    {
                        //beregn stigning i m^3 sekundet
                        double dif = Vandstand / 5 * 60;
                        if (Kanal.Vandstande.Count > 0)
                        {
                            dif = Vandstand - Kanal.Vandstande.Last().Vandstand;
                            dif = dif / (Dato - Kanal.Vandstande.Last().Dato).TotalSeconds;
                        }

                        if (Vandstand > Kanal.kapacitet * 0.75)
                        {
                            this.Pumper.StartAlle(Kanal);
                            if (Vandstand >= Kanal.kapacitet)
                                AddMessage("Kanal " + Kanal.Id + " er fuld!");
                            else
                                AddMessage("Kanal "+ Kanal.Id + " er mere end 75% fuld");
                        }
                        else
                            this.Pumper.TilpasPumper(dif, Kanal);
                    }
                }
                Kanal.SetVandstand(new ClsVandstand(Dato, Vandstand, Kanal));
            }
        }

        public void Write(string txt)
        {
            Console.WriteLine(txt);
        }

        public Kanal[] HentKanaler()
        {
            List<Kanal> Temp = new List<Kanal>();
            Kanal TK;
            foreach(ClsKanal K in this.Kanaler.Kanaler)
            {
                TK = new Kanal();

                TK.Id = K.Id;
                TK.kapacitet = K.kapacitet;
                TK.Level = K.Level;

                Temp.Add(TK);
            }

            return Temp.ToArray();
        }

        public Pumpe[] HentPumper()
        {
            Pumpe PTemp;
            List<Pumpe> Temp = new List<Pumpe>();
            foreach (ClsPumpe P in this.Pumper.Pumper)
            {
                PTemp = new Pumpe();

                PTemp.Id = P.Id;
                PTemp.TilId = P.Til.Id;
                PTemp.FraId = P.Fra.Id;
                PTemp.KvadratmeterVandSekundet = P.KvadratmeterVandSekundet;
                PTemp.On = P.On;
                PTemp.Defekt = P.Defekt;

                Temp.Add(PTemp);
            }

            return Temp.ToArray();
        }

        public bool StartPumpe(int PumpeId)
        {
            if (this.Pumper.Pumper.Count(val => val.Id == PumpeId) != 1)
                return false;

            if (this.C.StartPumpe(PumpeId))
            {
                this.Pumper.StartPumpe(PumpeId);
                return true;
            }
            else
            { 
                this.Pumper.DefektPumpe(PumpeId);
                AddMessage("Kan ikke få kontakt til pumpe " + PumpeId);
                return false;
            }
        }

        public bool SlukPumpe(int PumpeId)
        {
            if (this.Pumper.Pumper.Count(val => val.Id == PumpeId) != 1)
                return false;
            
            int Nr = 0;
            bool Res = false;
            while (Nr <= 5 && Res == false)
            {
                Res = this.C.SlukPumpe(PumpeId);
            }

            if (Nr >= 5 && Res == false)
            {
                this.Pumper.DefektPumpe(PumpeId);
                AddMessage("Kan ikke få kontakt til pumpe " + PumpeId);
                return false;
            }

            this.Pumper.SlukPumpe(PumpeId);
            return true;
        }

        public void StartFriFriAdministration()
        {
            this.FriAdministration = true;
        }

        public void StopFriFriAdministration()
        {
            this.FriAdministration = false;
        }

        public void DefektPumpe(int PumpeId, bool Defekt)
        {
            if (Defekt)
            {
                this.Pumper.DefektPumpe(PumpeId);
                AddMessage("Pumpe "+ PumpeId + " Defekt!");
            }
            else
                this.Pumper.ReparerPumpe(PumpeId);
        }
    }
}
